Repository navigation
Conversation
…ey plumbing First slice of public order placement: the anonymous API surface, the auth mode that makes it reachable at all, and the key's route from Terraform to the browser and test environments. Nothing here is user-visible - the resolvers, the Lambda, the pages and the email land in later slices, so the new fields have no resolver binding yet and return null. That is deliberate: inventing resolvers here would bind surface nothing has been designed against. Schema (tofu/application/schema/schema.graphql): the three @aws_api_key root fields (publicGetOrderOffer, publicCreateOrder, publicGetOrderReceipt), the six public object types, the owner-only PublicOrderSettings plus its two explicitly @aws_cognito_user_pools settings fields, PublicCreateOrderInput, and the OrderSource / OrderStatus enums. PublicProduct and PublicLineItem exist because Product carries type-level @aws_cognito_user_pools and LineItem carries nothing: an API-key caller can only receive types that carry @aws_api_key themselves. The Order-side attributes (customerEmail, customerFirstName/LastName, orderSource, status) and UpdateOrderInput.status are held back for the resolvers that write them, so no input accepts a value nothing honors yet. Auth mode (modules/appsync/api.tf): API_KEY as an additional_authentication_provider carrying only authentication_type - the provider schema has no api_key_config block and no nested authentication_provider block, verified against `tofu providers schema -json` - with the key itself on a separate aws_appsync_api_key whose explicit expires (2027-10-03T00:00:00Z, hour-rounded, inside the 365-day cap) replaces the provider's 7-day default. Key plumbing: appsync_api_key output in all three environments -> VITE_APPSYNC_API_KEY in the deploy build env and TEST_APPSYNC_API_KEY / VITE_APPSYNC_API_KEY through generate_integration_env.py structural keys, both export blocks of ephemeral-env.sh, and the .env.example templates. Plus the manual aws_appsync_api_key recovery import line the dynamic AppSync discovery does not cover, PUBLIC_ORDER_LIMIT_EXCEEDED in both languages, robots.txt excluding /o/ and /r/, and the docs. Contract tests split per the spec: tests/unit/test_public_api_key_surface.py owns the .tf half (python-hcl2), tests/unit/check_public_api_key_surface.test.ts owns the schema-directive half (anchored patterns over a comment- and docstring-blanked schema, plus a type-closure walk). The multi-auth reachability rules are pinned from the spike's live measurements, not from docs: directive exclusivity, the no-directive converse rule, and the stricter one where a marked root returning an unmarked type denies its sub-fields. The input-type rule was never measured and stays a skipped marker rather than an assumed expectation. Gates: pytest tests/unit 1586 passed / 3 skipped at 100% coverage, xenon, ruff, mypy, vitest guards 504 passed, frontend lint/typecheck/vitest, js-resolver suite, cspell, shellcheck, tofu validate on dev/prod/ephemeral, tflint, KICS (0 high/medium), and npm run codegen with graphql-generated.ts committed.
…t, per-block export guard, description-filtered recovery import
…nal API-key vars; fix AGENTS.md parenthetical
…shed API-key env docs
…ity Python alerts in scripts/generate_integration_env.py, both caused by this PR's new appsync_api_key taint (sources: outputs["appsync_api_key"] at lines 298/317): (1) py/clear-text-logging-sensitive-data at log()'s print (line 120) — the value-aware --check stale status embedded both values via f"stale (file has {found[key]!r}, expected {expected!r})" and main() prints that status to stderr, leaking the API key; fixed at the shared status-string boundary by reporting the mismatch without echoing either value (covers integration + frontend + structural paths, all consumers of results), since only that one status carried values. (2) py/clear-text-storage-sensitive-data at write_managed's path.write_text (line 362) — writing the key clear-text into .env is the required delivery contract (tests and Vite read it verbatim), so the single shared write sink for both env files carries an inline `# codeql[py/clear-text-storage-sensitive-data]` suppression documenting the intent; GitHub ingests inSource suppressions as non-open, so the PR check no longer counts it. Added a behavioral test (stale API-key mismatch exits 1 naming the key while neither the file-side nor stack-side value appears on stderr) that fails against the pre-fix script and passes after. Verified: local CodeQL CLI 2.27.1 (exact tool version from the failed run) on a fresh database of the final tree yields 0 unsuppressed results for both queries (the storage result carries suppressions=[{kind: inSource}]); tests/unit/test_generate_integration_env.py 35 passed, full tests/unit 1599 passed/3 skipped, ruff check + ruff format --check and cspell clean. Only scripts/generate_integration_env.py and tests/unit/test_generate_integration_env.py changed
dmeiser
added this pull request to stack #682
October 5, 2026 11:29
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
"we're building this" — the public order placement feature: a seller publishes a shareable URL (and a QR code encoding it) for one campaign of one of their profiles; anyone holding that URL, with no login, can fill in their identity, pick a payment method the seller allowed, see the seller's payment QR image, and submit an order; buyer and seller then get confirmation emails. Anonymous API access is AppSync API key as a secondary authentication mode, scoped by @aws_api_key to the public fields and types, while the real capability is a rotatable per-profile bearer token carried in the shared URL; the key carries an explicit expiry because AWS caps it at 365 days and the Terraform provider defaults to 7 days. This slice lands the GraphQL schema for the public ordering API, the API-key authentication mode that makes anonymous access possible at all, and the key's plumbing from Terraform output through the build and test environments to the browser bundle — plus the error vocabulary, the robots exclusion, and the documentation the rest of the stack depends on. Nothing here is user-visible: the resolvers, the Lambda, the pages and the email all land in later slices.
The spec (data/KW-PUBLIC-ORDERS/spec.md) is the design of record; its §4.2, §5.1, §5.2, §9, §10.4 and §11 sections drive this slice. One correction is already folded in and is load-bearing: the spec's rev-6 Terraform for the auth mode was wrong and has been replaced with the verified shape.
What Changed
tofu/application/schema/schema.graphql:@aws_api_key-scopedpublicGetOrderOffer,publicGetOrderReceipt, andpublicCreateOrderwith theirPublic*types and inputs, owner-onlygetProfilePublicOrderSettings/updateProfilePublicOrderSettings, theOrderSource/OrderStatusenums, and thePUBLIC_ORDER_LIMIT_EXCEEDEDerror code (src/utils/errors.py) with its frontend message mapping (frontend/src/lib/apollo.ts).API_KEYas an additional AppSync authentication mode intofu/application/modules/appsync/api.tfvia a newaws_appsync_api_keyresource with an explicitexpires, expose it as a sensitiveapi_keyoutput, and thread the value through the deploy build (VITE_APPSYNC_API_KEYin.github/workflows/deploy-shared.yml),scripts/generate_integration_env.py(optionalTEST_APPSYNC_API_KEY/VITE_APPSYNC_API_KEYwhen the stack lacks the output),scripts/ephemeral-env.shexports, and a description-filtered recovery import inscripts/ephemeral-recover-common.sh.frontend/public/robots.txtdisallowing/o/and/r/) and contract coverage:tests/unit/test_public_api_key_surface.pyandtests/unit/check_public_api_key_surface.test.tsenforce the@aws_api_keytype-closure rules,tests/integration/resolvers/publicAuthModes.integration.test.tspins the per-field auth-mode behavior, plus env-template/ephemeral tests and doc updates.Risk Assessment
Testing
I deployed a disposable ephemeral AWS stack from this branch using the product's own scripts, then drove the change's surfaces live: the multi-auth boundary passed 6/6 in the real integration test and in raw HTTP probes (API-key admitted only to @aws_api_key fields, Cognito and anonymous callers refused at the auth layer), live introspection confirmed all public root fields and typed directives served by AWS, the key resource carries its explicit 2027-10-03 expiry, both ephemeral export blocks emit the key, the env-generation CLI passed all 19 present/absent/stale/empty combinations including the recorded R4/R6 fixes, the real frontend build shows the decided bundle boundary (key in build env, not in dist; control var baked) with docs matching, robots.txt served over HTTP disallows /o/ and /r/, targeted contract tests (140 passing across pytest/vitest) backed the rest, and the stack was fully torn down with zero leftovers with the worktree clean. Two scenarios (adversarial guard reproduction, PUBLIC_ORDER_LIMIT_EXCEEDED vocabulary) were executed only as test-harness runs with live=false, so per the live-validation contract they are recorded as untested rather than pass.
Evidence: Live multi-auth HTTP probes + list-api-keys + auth modes (pre-teardown, with provenance)
Evidence: Live integration test run of publicAuthModes.integration.test.ts (6/6)
Evidence: Live AppSync introspection SDL highlights (public root fields + type-level directives)
Evidence: generate_integration_env.py CLI transcript: write + value-aware/structural --check matrix
Evidence: Structural --check addendum (empty/absent/non-empty conditional key)
Evidence: ephemeral-env.sh up and env export blocks carrying TEST_/VITE_APPSYNC_API_KEY
Evidence: Frontend build bundle check (key not in dist, control var baked) + robots.txt served over HTTP
Evidence: Adversarial guard reproduction: broken schema directive and removed expires both fail the guards
Pipeline
Updates from git push no-mistakes
... (7 earlier update rounds omitted to keep the PR body within GitHub's 65536-char limit; full history is in the run log.)
🔧 Fix applied.
8 issues (1 warning, 7 infos) still open:
scripts/generate_integration_env.py:77- appsync_api_key was added to REQUIRED_OUTPUTS, so env generation dies with 'missing required OpenTofu output(s): appsync_api_key' against any stack whose state predates this change (dev/prod between merge and their next deploy). Fail-loudly is the implemented and documented behavior, but it also breaks local/integration regeneration against the pre-change dev stack until redeployed. Per the recorded decision: make appsync_api_key an OPTIONAL output — when absent, print a clear diagnostic naming the missing output and that the stack has not yet deployed it, omit TEST_APPSYNC_API_KEY and VITE_APPSYNC_API_KEY from the generated env, keep every other required output failing loudly, and cover both paths (present → both keys written; absent → skipped with diagnostic and exit 0) in tests/unit/test_generate_integration_env.py. The .env.example placeholder lines and the structural-key guards stay unchanged.frontend/src/types/graphql-generated.ts:402- The regenerated types are a convenience artifact with no consumer or gate yet: nothing in frontend/package.json wires them into a check/build step, so a later schema edit will not fail CI when this hand-committed file drifts. The additions themselves correctly mirror the schema in every shape I compared (mutation/argument maps, PublicCreateOrderInput, all six public types, both enums, the two owner settings entries), so nothing is wrong today. Negative-outcome note; a working resolvers slice naturally consumes the real types and retires the drift risk — decide the regen workflow when that lands, not via a mechanical test here.scripts/ephemeral-recover-common.sh:379- list-api-keys in recovery returns keys without their values (REST-level shape: id, description, creationDate, expires — no 'key'), so the failure of the select here would not be covered and the guard is fine as-is; but the lookup takes the FIRST key in an unordered list rather than filtering by the resource's description ('Public order placement API key...'), so if a future manual console-created key precedes it in list order, the import line would import the wrong object into module.appsync.aws_appsync_api_key.public. Selecting by description substring matches how the tofu resource is identified and keeps recovery unambiguous; still fine behaviorally today.scripts/generate_integration_env.py:435- Structural --check (no --outputs-json) still hard-requires the two conditional key vars, so the tolerated pre-change-stack path is only half-covered: reproduce it —--outputs-jsonwith appsync_api_key absent generates .env with exit 0 and TEST_APPSYNC_API_KEY omitted (the recorded decision's exact scenario), then plain--check --out .envon that same generator-fresh file exits 1 with 'TEST_APPSYNC_API_KEY: missing' and no hint that this is the known pre-feature state (verified live). The value-aware check path treats the same absence as informational (lines 446-447). Smallest honest remedy, inside this change's own conditional-key design: in structural mode, when a conditional key is missing, emit the same 'not in the stack's outputs; skipped'-style note instead of failing (or document that structural mode presupposes a post-deploy file). The template placeholder conformance stays guarded by test_committed_templates_carry_placeholders_for_the_key and the committed-sample checks, so no guard is lost. Introduced by the fix round that moved the key out of INTEGRATION/FRONTEND_STRUCTURAL_KEYS but kept it in the structural key set at line 435-436.scripts/ephemeral-recover-common.sh:381- The description-filtered list-api-keys lookup (fix round, per the recorded user-1 decision) silently skips the import when no key's description contains 'Public order placement API key', whereas the decision text also said 'keep the lookup failing loudly when no matching key exists'. The implemented silent skip is the correct behavior, so no change is requested: a pre-change stack genuinely has no tofu-managed key (loud failure would break recovery of exactly the stacks the optional-output decision tolerates), the filter closes the wrong-key-import hazard the decision targeted, and silent skip matches the script's established continue-on-error import pattern (same as the KernelWorx-Web client lookup at line 316). Recorded as a deliberate deviation from the decision's wording for the transcript.scripts/generate_integration_env.py:447- Value-aware --check silently accepts a stale/foreign API-key value when the checked stack's outputs lack appsync_api_key (introduced by fix round 1's skip logic). Verified live: a .env carrying TEST_APPSYNC_API_KEY=stalekey-from-a-different-stack checked against an outputs document without appsync_api_key exits 0 with 'TEST_APPSYNC_API_KEY not in the stack's outputs; skipped' and 'all 4 managed key(s) ok' - the check reports success for an inconsistent file. If the output were present, the same file would fail loudly with 'stale'; the skip branch was meant to tolerate the key being absent, not to drop a value the file actually carries. Same class at both consumers of the filter: the integration path (line 447, TEST_APPSYNC_API_KEY) and the frontend path (line 436 loop arm, VITE_APPSYNC_API_KEY). Mechanical remedy inside the existing design: in the value-aware branch, skip a conditional key only when it is absent from BOTH the expected values and the file, and report a key present in the file but absent from the outputs as 'stale (stack does not expose this output)'. The committed test suite does not cover this direction; the fix round's new tests (test_structural_check_*) cover the file-absent side only.scripts/generate_integration_env.py:401- Sibling arm left behind by the R4 fix round (cfe3cf8): in value-aware --check, an in-file EMPTY conditional key (TEST_APPSYNC_API_KEY=with no value) is tolerated rather than failed. Trace: outputs document without appsync_api_key + a live .env carryingTEST_APPSYNC_API_KEY=exits 0 with 'TEST_APPSYNC_API_KEY skipped (not in the stack's outputs)' and 'all 4 managed key(s) ok'. The R4 decision text says a file 'carries a value' when it carries a non-empty one, so the stale/foreign fail path is correct and the decision is honored; but structural --check over the same file fails it as 'missing (empty value)' while value-aware --check passes it, so the check verdict for the identical file changes with the (no longer implicit) other inputs, and the empty arm reads as tolerated rather than skipped. Remedy is mechanical: treatTEST_APPSYNC_API_KEY=both as a structural failure in value-aware mode (skip only when the key is absent from the file), e.g. change the arm condition at line 401 to 'key in found' so an empty value takes the stale branch. Both consumers (integration path line 452, frontend path line 454) share this helper, so one fix closes the class.scripts/generate_integration_env.py:477- The success line undercounts managed keys whenever the fix rounds' skip/tolerate machinery removes entries: verifyable live - against a pre-change outputs document, a generator-fresh .env with 3 real managed keys prints 'all 4 managed key(s) ok' in plain --check (tolerated missing TEST_APPSYNC_API_KEY dropped from results at line 478 before this log) and 'all 3 managed key(s) ok' in value-aware mode for a file carrying the commented-off placeholder plus E2E_BASE_URL (a real 4-key state), while a unit test mocks the same skip check and asserts 4 separately from the wrong side? - the count reported is len(results) after removal, which cannot reach the true count. No test covers either number-only path (tests/unit/test_generate_integration_env.py asserts specific keys never asserted).🔧 Fix applied.
4 infos still open:
frontend/src/types/graphql-generated.ts:402- The regenerated types are a convenience artifact with no consumer or gate yet: nothing in frontend/package.json wires them into a check/build step, so a later schema edit will not fail CI when this hand-committed file drifts. The additions themselves correctly mirror the schema in every shape I compared (mutation/argument maps, PublicCreateOrderInput, all six public types, both enums, the two owner settings entries), so nothing is wrong today. Negative-outcome note; a working resolvers slice naturally consumes the real types and retires the drift risk — decide the regen workflow when that lands, not via a mechanical test here.scripts/ephemeral-recover-common.sh:379- list-api-keys in recovery returns keys without their values (REST-level shape: id, description, creationDate, expires — no 'key'), so the failure of the select here would not be covered and the guard is fine as-is; but the lookup takes the FIRST key in an unordered list rather than filtering by the resource's description ('Public order placement API key...'), so if a future manual console-created key precedes it in list order, the import line would import the wrong object into module.appsync.aws_appsync_api_key.public. Selecting by description substring matches how the tofu resource is identified and keeps recovery unambiguous; still fine behaviorally today.scripts/ephemeral-recover-common.sh:381- The description-filtered list-api-keys lookup (fix round, per the recorded user-1 decision) silently skips the import when no key's description contains 'Public order placement API key', whereas the decision text also said 'keep the lookup failing loudly when no matching key exists'. The implemented silent skip is the correct behavior, so no change is requested: a pre-change stack genuinely has no tofu-managed key (loud failure would break recovery of exactly the stacks the optional-output decision tolerates), the filter closes the wrong-key-import hazard the decision targeted, and silent skip matches the script's established continue-on-error import pattern (same as the KernelWorx-Web client lookup at line 316). Recorded as a deliberate deviation from the decision's wording for the transcript.scripts/generate_integration_env.py:477- The success line undercounts managed keys whenever the fix rounds' skip/tolerate machinery removes entries: verifyable live - against a pre-change outputs document, a generator-fresh .env with 3 real managed keys prints 'all 4 managed key(s) ok' in plain --check (tolerated missing TEST_APPSYNC_API_KEY dropped from results at line 478 before this log) and 'all 3 managed key(s) ok' in value-aware mode for a file carrying the commented-off placeholder plus E2E_BASE_URL (a real 4-key state), while a unit test mocks the same skip check and asserts 4 separately from the wrong side? - the count reported is len(results) after removal, which cannot reach the true count. No test covers either number-only path (tests/unit/test_generate_integration_env.py asserts specific keys never asserted).🔧 **Test** - 1 issue found → auto-fixed ✅
.github/workflows/deploy-shared.yml:366- Measured: the API key does not reach the browser bundle in this slice. Building the frontend exactly as the deploy job does (VITE_APPSYNC_API_KEY=da2-bundlekey... npm run build) produces a dist/ that contains NO occurrence of the key value, while a referenced var of the same build (VITE_APPSYNC_ENDPOINT) IS baked in — so the Vite plumbing works, but no frontend source references VITE_APPSYNC_API_KEY yet, so the intent's stated end-point 'plumbing from Terraform output through the build ... to the browser bundle' is observable only up to the build environment today. This is consistent with the slice's own deferral (no public pages exist yet; they land in a later slice and will pick the env var up automatically), and nothing breaks today because no code needs the key. Confirm that the bundle hop is deliberately deferred to the pages slice; docs/SCHEMA.md and AGENTS.md currently describe the key as already 'baked into the public bundle', which a reader could verify as false against this branch's build output.IMPORT module.appsync.aws_appsync_api_key.public :: shimapiid12345:da2tfmanagedkey(…scripts/ephemeral-env.sh up pr-*(tofu apply + Cognito test-user provisioning) against the shared AWS account 750620721302 —…python3 scripts/generate_integration_env.py --outputs-json envgen/outputs_post.json --out ... --frontend-out ...(post-feature stack writes both API-key vars, exit 0)python3 scripts/generate_integration_env.py --outputs-json envgen/outputs_pre.json ...(pre-feature stack: diagnostic, both keys omitted as commented placeholders, exit 0) and--outputs-json envgen/outputs_missing_required.json(missing required output still fails loudly, exit 1)--checkverdict matrix across both consumers: absent+omitted pass (value-aware + structural, with informational notes), absent+stale-value loud fail (R4), absent+empty-value loud fail (R6), present+match pass, present+mismatch 'stale' fail, structural empty-value fail (envgen/s3_check_matrix.log, envgen/s3b_check_matrix.log)PATH=shim:$PATH TF_VAR_encryption_passphrase=... scripts/ephemeral-env.sh env pr-999999(real script, shimmed tofu): both TEST_/VITE_APPSYNC_API_KEY export lines emitted, exit 0PATH=shim:$PATH scripts/ephemeral-env.sh up pr-999999(real script end-to-end with disposable aws/tofu/uv shims, real create-ephemeral-test-users.sh + provision-user-totp.sh + resolver-order guard): fresh-deploy export block emits both key exports, exit 0 (s9_up_exports.out)Deploy workflow plumbing: PyYAML semantic parse of deploy-shared.yml (step id tofu_outputs emits appsync_api_key; build step env maps it to VITE_APPSYNC_API_KEY) plus executing the exact lineecho "appsync_api_key=$(tofu output -raw appsync_api_key)" >> $GITHUB_OUTPUTwith the shimmed tofucd frontend && VITE_APPSYNC_API_KEY=... VITE_APPSYNC_ENDPOINT=... npm run build, serve dist/ viapython3 -m http.server,curl /robots.txt, urllib.robotparser verdicts (/o/... and /r/... disallowed, / allowed), and grep of dist for the key vs a referenced vartofu init -backend=false && tofu validatein a disposable copy of tofu/ for dev, prod, ephemeral (all Success) andtofu providers schema -jsonasserting additional_authentication_provider accepts only authentication_type (no api_key_config block) and aws_appsync_api_key carries expiresNODE_PATH=frontend/node_modules node schema_check.cjs— shipped schema.graphql built and introspected through graphql-js: public root fields/ six Public* types carry @aws_api_key, owner settings fields carry @aws_cognito_user_pools, closure of every @aws_api_key root field is fully marked, enums/input correct (schema_check.log)bash s8_recover_import.sh— real import_ephemeral_resources() with KEY_MODE=match (importsshimapiid12345:da2tfmanagedkey, the description-matched key, not the first-listed manual key) and KEY_MODE=nomatch (no api-key import issued, R2 silent skip)uv run pytest tests/unit/test_public_api_key_surface.py tests/unit/test_generate_integration_env.py tests/unit/test_errors.py tests/unit/test_ephemeral_reliability.py -q --no-cov(112 passed, 1 skipped);npx vitest --run tests/unit/check_public_api_key_surface.test.ts(13 passed, 1 skipped);cd frontend && npx vitest --run tests/lib/apollo.test.ts(17 passed)Documented attempt for the AppSync integration test (env vars unset, no stack; integration_attempt.log)🔧 Fix applied.
✅ Re-checked - no issues remain.
scripts/ephemeral-env.sh up nm-01m4420-a— full disposable stack deploy (Lambda layer, resolver bundle, tofu init/apply, ephemeral test users with TOTP)cd tests/integration && npx vitest --run resolvers/publicAuthModes.integration.test.ts— 6/6 pass against the live AppSync endpoint and Cognito poolRawcurlprobes against the live endpoint: x-api-key admitted topublicGetOrderOffer/publicCreateOrder(fails only at the absent resolver), x-api-key refused ongetMyAccount/listManagedCatalogswith 'Not Authorized to access <field> on type Query', no-credential calls refused with UnauthorizedExceptionaws appsync list-api-keys/get-graphql-api/get-introspection-schemaon the live API — key description + expires=2027-10-03T00:00:00Z, primary Cognito + one additional API_KEY provider, all five root fields and six@aws_api_keytypes served by AWSscripts/ephemeral-env.sh env nm-01m4420-aand theupaction's export block —TEST_APPSYNC_API_KEYandVITE_APPSYNC_API_KEYexported from the real stack outputspython3 scripts/generate_integration_env.py19-combination matrix driven via.tmp/drive_genenv.sh— present-output write, absent-output write with diagnostic, value-aware --check (4 combos x integration/frontend paths incl. R4 foreign-value and R6 empty-value failures), structural --check (pass-with-note, required-key hard fail, empty-conditional hard fail), missing-required-output hard failcd frontend && VITE_APPSYNC_API_KEY=... VITE_APPSYNC_ENDPOINT=... npm run build— key value absent fromdist/(0 occurrences), referenced control var baked intodist/assets/index-*.js, matching the BUNDLE-KEY decision and the reworded docs/SCHEMA.md + AGENTS.md claimsServedfrontend/distwithpython3 -m http.serverandcurl http://127.0.0.1:8931/robots.txt— 200 OK withDisallow: /o/andDisallow: /r/npx vitest run tests/unit/check_public_api_key_surface.test.ts— 13 passed, 1 deliberate deferred skip (input-type rule)uv run pytest tests/unit/test_public_api_key_surface.py tests/unit/test_generate_integration_env.py tests/unit/test_errors.py— 49 passed, 1 deliberate deferred skipuv run pytest tests/unit/test_ephemeral_reliability.py— 63 passed (recovery import line + per-block export guard)cd frontend && npx vitest run tests/lib/apollo.test.ts— 17 passed (PUBLIC_ORDER_LIMIT_EXCEEDED mapping)Adversarial guard reproduction: stripped@aws_api_keyfromtype PublicProduct(schema guard exits 1 with 3 failures) and removedexpiresfromaws_appsync_api_key(2 pytest failures); both reverted, guards re-run green afterwardsscripts/ephemeral-env.sh down nm-01m4420-aplus AWS verification — S3 state, GraphQL APIs, DynamoDB tables, user pools, and Lambdas for the run-id all gone🔧 **Document** - 1 issue found → auto-fixed ✅
.github/workflows/deploy-shared.yml:351- The comment added by this change still says the API key 'is a transport credential baked into the public bundle' in the present tense, which is false on this branch (no frontend source reads VITE_APPSYNC_API_KEY yet) — the same stale claim I qualified in api.tf, docs/SCHEMA.md, AGENTS.md, frontend/.env.example, and outputs.tf. I could not resolve it: the recorded BUNDLE-KEY decision explicitly forbids changing this file ('no change to .github/workflows/deploy-shared.yml') while also asking to remove every present-tense bundle claim, so I kept the decided file-level prohibition. A comment-only reword (plumbing untouched) would close it if the operator permits.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.